# -*-coding:utf-8 -*-
from django.contrib.gis.db import models
from django.conf import settings
from django.dispatch import receiver
import os
import hashlib
from xpinyin import Pinyin
from core.util import create_qrcode
import os
import uuid
from django.contrib.staticfiles.finders import default_storage
from django.core.files.base import ContentFile
from datetime import datetime
from django.db.models import Count
from easy_thumbnails.fields import ThumbnailerImageField
from django.core.files.base import ContentFile
from easy_thumbnails.files import get_thumbnailer

from urllib.parse import urlparse
from django.db.models.signals import m2m_changed, post_save
from django.dispatch import receiver
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish
import json
NOTIFY_BROKER = getattr(settings, 'NOTIFY_BROKER', None)



# Create your models here.
DEV_STATE_UNKOWN = "UNKOWN"  # 未知
DEV_STATE_ACTIVE = "ACTIVE"  # 活动
DEV_STATE_POWROFF = "POWROFF"  # 关机
DEV_STATE_FAULT = "FAULT"  # 故障
DEV_STATE_REPAIR = "REPAIR"  # 检修


def box_status_color(status):
        if status == DEV_STATE_ACTIVE:
            return "#00ff00"
        elif status == DEV_STATE_FAULT:
            return "#ff0000"
        elif status == DEV_STATE_POWROFF:
            return "#ff9900"
        elif status == DEV_STATE_REPAIR:
            return "#0000ff"
        else:
            return "#666666"


class DeviceManager(models.Manager):
    def stat_status(self):
        qs = self.get_queryset()
        qs = qs.values('status',).annotate(count=Count('status'))
        kv = {obj["status"]: obj["count"] for obj in qs}
        stats = [{'title': v, 'status': k, 'color': box_status_color(k), 'count': 0} for (k, v) in BoardBox.BOX_STATUS]
        for obj in stats:
            obj["count"] = kv.get(obj['status'], 0)
        return stats


class Device(models.Model):
    objects = DeviceManager()
    DEV_STATUS = ((DEV_STATE_ACTIVE, u'活动'), (DEV_STATE_POWROFF, u'关机'), (DEV_STATE_FAULT, u'故障'), (DEV_STATE_REPAIR, u'检修'), (DEV_STATE_UNKOWN, u'未知'), )
    # DEV_ROLES = ((DEV_ROLE_IOT, u'感知节点'), (DEV_ROLE_NG, u'数据网关'), (DEV_ROLE_PC, u'个人电脑'), (DEV_ROLE_SVR, u'服务器'), )
    id = models.CharField("节点ID", max_length=12, primary_key=True, help_text="字母和数字组合，不能重复，按照你喜欢的方式编码，不设置系统自动编码", editable=False)
    name = models.CharField(u'设备名称', max_length=64, help_text="节点名称")
    vid = models.CharField(u'识别代码', max_length=16, default="0000000000000000")
    spinyin = models.CharField(u'简拼码', max_length=25, null=True, blank=True)
    qrcode = models.ImageField(u'二维码', max_length=200, upload_to='core/boardbox/qrcode/', blank=True, null=True,)
    createdat = models.DateTimeField(u'创建时间', auto_now_add=True)
    updatedat = models.DateTimeField(u'更新于', auto_now=True)
    department = models.ForeignKey('org.department', verbose_name=u'所属部门', on_delete=models.SET_NULL, blank=True, null=True)
    createby = models.ForeignKey(settings.AUTH_USER_MODEL,  null=True, blank=True, verbose_name='创建账号', on_delete=models.SET_NULL)
    nrole = models.CharField(u'节点类型', max_length=16, db_index=True, default="PC")

    # 存放位置
    address = models.CharField(u'安装位置', max_length=255, null=True, blank=True)
    location = models.PointField("GIS位置", srid=4326, null=True, blank=True)

    brand = models.CharField(u'品牌', max_length=150, blank=True, null=True)
    provider = models.CharField(u'提供商', max_length=64, blank=True, null=True)
    contactor = models.CharField(u'联系人', max_length=64, blank=True, null=True)
    phone = models.CharField(u'联系电话', max_length=64, blank=True, null=True)

    # 显示信息
    pic1 = ThumbnailerImageField(u'设备正视图', upload_to='asset/photo/', null=True, blank=True, default='', help_text=u'正视图')
    pic2 = ThumbnailerImageField(u'设备侧视图', upload_to='asset/photo/', null=True, blank=True, default='', help_text=u'侧视图')
    pic3 = ThumbnailerImageField(u'设备俯视图', upload_to='asset/photo/', null=True, blank=True, default='', help_text=u'俯视图')

    status = models.CharField(u"状态", max_length=16, default=DEV_STATE_UNKOWN, choices=DEV_STATUS)
    state_time = models.DateTimeField('状态更新时间', default=datetime.now())
    # cutscreen = models.ImageField(u'最近显示截屏', max_length=200, upload_to='core/boardbox/screen/', blank=True, null=True,)
    # screen_time = models.DateTimeField(u'截屏时间', null=True, blank=True)

    memo = models.CharField(u'备注', max_length=255, null=True, blank=True)

    def new_id(self):
        td = datetime.now()
        d = td.year-2000+td.month+td.day
        t = td.hour+td.minute+td.second
        _id = "%03d%03d%06d" % (d, t, td.microsecond)
        self.id = _id[:12]

    def create_vid(self):
        (department_id, user_id) = (None, None)
        if self.department:
            department_id = self.department.id
           
        _str = u"%s-%d-%d" % (self.id, department_id or 0, user_id or 0)
        m = hashlib.md5(_str.encode('utf-8'))
        res = "%s" % m.hexdigest()[8:-8]
        self.vid = res.upper()

    def create_qr_code(self):
        obj_id = u'%s.%s.%s' % (self._meta.app_label,
                                self.__class__.__name__, self.id)
        output = create_qrcode(obj_id)
        filename = os.path.join(self._meta.get_field(
            'qrcode').upload_to, '%s.png' % str(uuid.uuid4()))
        path = default_storage.save(filename, ContentFile(output.getvalue()))
        self.qrcode = path

    def create_spinyin(self):
        if not self.name or self.name == '':
            return
        py = Pinyin()
        self.spinyin = py.get_initials(self.name, u'')[:20]

    def clean(self):
        if not self.name:
            self.create_spinyin()

    def __str__(self):
        return u'%s' % self.name

    def __unicode__(self):
        return self.__str__()

    @staticmethod
    def autocomplete_search_fields():
        return 'spinyin', 'name'

    class Meta:
        # abstract=True
        #managed = False
        verbose_name_plural = verbose_name = "设备"

    def save(self, *args, **kwargs):
        # self.vid = self.create_md5id()
        self.create_spinyin()
        if not self.qrcode:
            self.create_qr_code()
        super().save(*args, **kwargs)


class BoardBoxManager(models.Manager):
    def stat_status(self):
        qs = self.get_queryset()
        qs = qs.values('status',).annotate(count=Count('status'))

        kv = {obj["status"]: obj["count"] for obj in qs}
        stats = [{'title': v, 'status': k, 'color': box_status_color(k), 'count': 0} for (k, v) in BoardBox.DEV_STATUS]
        for obj in stats:
            obj["count"] = kv.get(obj['status'], 0)
        return stats

class BoardBox(Device):
    objects = BoardBoxManager()
    HOST_PC = "PC"  # PC机
    HOST_MINIPC = "MINIPC"  # 迷你PC
    HOST_OPS = "OPS"  # OPS
    OS_TYPES = (('LINUX', 'LINUX'), ('WIN7', 'Windows 7'), ('WIN7', 'Windows 10'), ('WIN RT', 'Windows RT'))
    HOST_TYPES = ((HOST_PC, u'PC机'), (HOST_MINIPC, u'迷你PC'), (HOST_OPS, u'OPS'),)
    citycode = models.CharField(u'城市代码', max_length=255, null=True, blank=True,)
    # 主机信息
    ip_addr = models.CharField(u'IP地址', max_length=255, null=True, blank=True)
    osType = models.CharField(u'系统类型', max_length=16, null=True, blank=True, default="LINUX", choices=OS_TYPES)
    hostType = models.CharField(u'主机类型', max_length=16, choices=HOST_TYPES, default=HOST_PC)
    boxVer = models.CharField(u'主机型号', max_length=5, default='00000')
    size = models.PositiveSmallIntegerField(u'屏幕尺寸', default=21)
    ratio = models.CharField(u'分辨率', max_length=255, null=True, blank=True)

    # 显示信息
    photo = models.ImageField(u'实拍照片', max_length=200, upload_to='asset/boardbox/photo/', blank=True, null=True)
    bg_image = models.ImageField(u'背景照片', max_length=200, upload_to='asset/boardbox/photo/', blank=True, null=True, help_text=u'用于显示在展板界面的背景图片，不设置则为纯色背景。')
    welcome = models.CharField(u'欢迎词', max_length=255, null=True, blank=True)
    viewmode = models.CharField(u'内容频道', max_length=255, null=True, blank=True)
    shutdown_time = models.TimeField(u'自动关机时间', blank=True, null=True)


    def get_department_name(self):
        if self.department:
            return u"%s" % self.department.name
        else:
            return None

    def create_qr_code(self):
        obj_id = u'%s.%s.%s' % (self._meta.app_label,
                                self.__class__.__name__, self.id)
        output = create_qrcode(obj_id)
        filename = os.path.join(self._meta.get_field(
            'qrcode').upload_to, '%s.png' % str(uuid.uuid4()))
        path = default_storage.save(filename, ContentFile(output.getvalue()))
        self.qrcode = path

    def create_spinyin(self):
        if not self.name or self.name == '':
            return
        py = Pinyin()
        self.spinyin = py.get_initials(self.name, u'')[:20]

    def clean(self):
        if not self.name:
            self.create_spinyin()

    def __str__(self):
        return u'%s' % self.name

    def __unicode__(self):
        return self.__str__()

    @staticmethod
    def autocomplete_search_fields():
        return 'spinyin', 'name'

    class Meta:
        # abstract=True
        #managed = False
        verbose_name_plural = verbose_name = "终端展板"

    def save(self, *args, **kwargs):
        # self.vid = self.create_md5id()
        self.create_spinyin()
        if not self.qrcode:
            self.create_qr_code()
        super().save(*args, **kwargs)


class CutScreen(models.Model):
    box = models.ForeignKey("asset.BoardBox", verbose_name=u'设备', on_delete=models.CASCADE,)
    time = models.DateTimeField(u'时间', auto_now_add=True)
    screen = models.ImageField(u'截屏', max_length=200, upload_to='asset/boardbox/screen/%Y/%m', blank=True, null=True,)

    def __str__(self):
        return u"%s" % self.box

    def __unicode__(self):
        return self.__str__()

    class Meta:
        verbose_name_plural = verbose_name = "终端截屏"


class CpuPerf(models.Model):
    box = models.ForeignKey("asset.BoardBox", verbose_name=u'设备', on_delete=models.CASCADE,)
    time = models.DateTimeField(u'时间', db_index=True, auto_now_add=True)
    totle = models.BigIntegerField(u'总量', default=0)
    usage = models.BigIntegerField(u'使用', default=0)
    rate = models.FloatField(u'使用率', default=0)

    def __str__(self):
        return u"%s" % self.box

    def __unicode__(self):
        return self.__str__()

    class Meta:
        verbose_name_plural = verbose_name = "CPU性能"


class MemPerf(models.Model):
    box = models.ForeignKey("asset.BoardBox", verbose_name=u'设备', on_delete=models.CASCADE)
    time = models.DateTimeField(u'时间', db_index=True, auto_now_add=True)
    totle = models.BigIntegerField(u'总量', default=0)
    usage = models.BigIntegerField(u'使用', default=0)
    free = models.BigIntegerField(u'空闲', default=0)
    buffers = models.BigIntegerField(u'缓冲', default=0)
    cache = models.BigIntegerField(u"缓存", default=0)
    rate = models.FloatField(u'使用率', default=0)

    def __str__(self):
        return u"%s" % self.box

    def __unicode__(self):
        return self.__str__()

    class Meta:
        verbose_name_plural = verbose_name = "内存性能"


class NetPerf(models.Model):
    box = models.ForeignKey("asset.BoardBox", verbose_name=u'设备', on_delete=models.CASCADE)
    time = models.DateTimeField(u'时间', db_index=True, auto_now_add=True)
    recv = models.BigIntegerField(u'接收', default=0)
    send = models.BigIntegerField(u'发送', default=0)
    recv_speed = models.BigIntegerField(u'接收速度', default=0)
    send_speed = models.BigIntegerField(u'发送速度', default=0)

    def __str__(self):
        return u"%s" % self.box

    def __unicode__(self):
        return self.__str__()

    class Meta:
        verbose_name_plural = verbose_name = "网络性能"


class DiskPerf(models.Model):
    box = models.ForeignKey("asset.BoardBox", verbose_name=u'设备', on_delete=models.CASCADE)
    time = models.DateTimeField(u'时间', db_index=True, auto_now_add=True)
    totle = models.BigIntegerField(u'总量', default=0)
    usage = models.BigIntegerField(u'使用', default=0)
    rate = models.FloatField(u'使用率', default=0)
    read_speed = models.BigIntegerField(u'接收速度', default=0)
    write_speed = models.BigIntegerField(u'发送速度', default=0)

    def __str__(self):
        return u"%s" % self.box

    def __unicode__(self):
        return self.__str__()

    class Meta:
        verbose_name_plural = verbose_name = "磁盘性能"


# @receiver(models.signals.pre_save, sender=BoardBox)
# def auto_delete_file_on_change(sender, instance, **kwargs):
#     """
#     Deletes old file from filesystem
#     when corresponding `MediaFile` object is updated
#     with new file.
#     """
#     if not instance.pk:
#         return False

#     try:
#         old_file = BoardBox.objects.get(pk=instance.pk).cutscreen
#     except BoardBox.DoesNotExist:
#         return False

#     new_file = instance.cutscreen
#     if not old_file == new_file:
#         if os.path.isfile(old_file.path):
#             os.remove(old_file.path)


# @receiver(models.signals.post_delete, sender=BoardBox)
# def auto_delete_file_on_delete(sender, instance, **kwargs):
#     """
#     Deletes file from filesystem
#     when corresponding `MediaFile` object is deleted.
#     """
#     if instance.cutscreen:
#         if os.path.isfile(instance.cutscreen.path):
#             os.remove(instance.cutscreen.path)


@receiver(post_save, sender=BoardBox)
def auto_push_change_info(sender, instance, **kwargs):
    p = urlparse(NOTIFY_BROKER)
    host, port = p.netloc.split(":")
    topic = "edboard/device/%s/changed" % instance.pk
    # msg = ''
    publish.single(topic, "1", hostname=host, port=int(port))
